﻿
using System;
using System.Collections.Generic;
namespace EquipmentPanelTest.Data
{
    public class CoordinateMatrix<T> where T : ICell
    {
        public int RowsCount { get; private set; }

        public int ColumnsCount { get; private set; }

        public CoordinateMatrix()
            : this(0, 0)
        {
        }

        public CoordinateMatrix(int rowsCount, int columnsCount)
        {
            Setup(rowsCount, columnsCount);
        }

        #region Public methods

        public T[] this[int index]
        {
            get
            {
                return itemsMatrix[index];
            }
        }

        public void Clear()
        {
            Setup(0, 0);
        }

        public void Setup(int rowsCount, int columnsCount)
        {
            RowsCount = rowsCount;
            ColumnsCount = columnsCount;

            itemsMatrix = new T[RowsCount][];
            for (int i = 0; i < RowsCount; ++i)
                itemsMatrix[i] = new T[ColumnsCount];
        }

        public IEnumerable<T> ToEnumerable()
        {
            List<T> result = new List<T>();

            for (int i = 0; i < RowsCount; ++i)
            {
                for (int j = 0; j < ColumnsCount; ++j)
                {
                    result.Add(itemsMatrix[i][j]);
                }
            }

            return result;
        }

        public IEnumerable<T> ApplyFilter(Predicate<T> filter)
        {
            List<T> result = new List<T>();

            for (int i = 0; i < RowsCount; ++i)
            {
                for (int j = 0; j < ColumnsCount; ++j)
                {
                    T item = itemsMatrix[i][j];

                    if (filter(item))
                        result.Add(item);
                }
            }

            return result;
        }

        public void ForEach(Action<T> action)
        {
            for (int i = 0; i < RowsCount; ++i)
            {
                for (int j = 0; j < ColumnsCount; ++j)
                {
                    T item = itemsMatrix[i][j];
                    action(item);
                }
            }
        }

        public bool CheckFreeArea(T cell, int rowsCount, int columnsCount)
        {
            if (cell.IsOccupied)
                return false;

            if (cell.Row + rowsCount > RowsCount || cell.Column + columnsCount > ColumnsCount)
                return false;

            int startRow = cell.Row;
            int endRow = startRow + rowsCount;
            int startColumn = cell.Column;
            int endColumn = startColumn + columnsCount;

            for (int i = startRow; i < endRow; ++i)
            {
                for (int j = startColumn; j < endColumn; ++j)
                {
                    if (itemsMatrix[i][j].IsOccupied)
                        return false;
                }
            }


            return true;
        }

        public bool CheckFreeArea(int rowIndex, int columnIndex, int rowsCount, int columnsCount)
        {
            T cell = itemsMatrix[rowIndex][columnIndex];
            return CheckFreeArea(cell, rowsCount, columnsCount);
        }

        #endregion

        #region Private fields

        T[][] itemsMatrix;

        #endregion
    }

    public interface ICell
    {
        bool IsOccupied { get; }
        int Row { get; }
        int Column { get; }
    }
}
